(module datum mzscheme

  (require "require.ss")
  (require-contracts)
  (require-lists)
  (require-compare)
  
  (provide/contract
   [datum? predicate/c]
   [datum=? ((eta datum?) (eta datum?) . -> . boolean?)]
   [datum<? ((eta datum?) (eta datum?) . -> . boolean?)]
   [datum-list=? ((listof (eta datum?)) (listof (eta datum?)) . -> . boolean?)]
   [datum-bindings=?
    ((listof (list/c (eta datum?) any/c)) (listof (list/c (eta datum?) any/c))
     . -> . boolean?)]
   [datum-compare ((eta datum?) (eta datum?) . -> . (integer-in -1 1))]
   [datum-hash ((eta datum?) . -> . integer?)])

  (define (datum? v)
    (or (number? v)
        (symbol? v)
        (string? v)))

  (define datum-compare default-compare)
  (define datum<? (<? datum-compare))
  (define datum=? (=? datum-compare))

  (define datum-hash equal-hash-code)

  (define (datum-list=? one two)
    (and (= (length one) (length two))
         (andmap datum=?
                 (mergesort one datum<?)
                 (mergesort two datum<?))))

  (define (datum-bind<? one two)
    (datum<? (first one) (first two)))
  
  (define (datum-bindings=? one two)
    (and (= (length one) (length two))
         (andmap (lambda (bind-one bind-two)
                   (and (datum=? (first bind-one) (first bind-two))
                        (datum=? (second bind-one) (second bind-two))))
                 (mergesort one datum-bind<?)
                 (mergesort two datum-bind<?))))

  )